package view;

import controllers.CheckSyntacticValidationProgressTask;
import controllers.SyntacticValidator;
import controllers.TransactionResultServiceControl;
import controllers.filters.FileReaderFilter;
import controllers.filters.PersistenceFilter;
import controllers.filters.SenderFilter;
import controllers.filters.SyntacticValidatorFilter;
import controllers.pipes.Persistence2SenderPipe;
import controllers.pipes.Reader2ValidatorPipe;
import controllers.pipes.Validator2PersistencePipe;
import entities.Archive;
import java.io.*;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import ws.transaction.TransactionResult;

/**
 * @version 1.0 @date 13/04/2012
 * @author john
 */
public class ProgressPane extends GridPane {
  
  private final double minWidth = 400;
  private final double minHeight = 120;
  private final double prefPanelHeight = 80;
  private final String showText = "Mostrar Detalles";
  private final String hideText = "Ocultar Detalles";
  private final int syntactic = 1;
  private final int semantic = 2;
  private final int timeBetweenChecks = 1000;
  private long totalLinesNumber;
  private long totalSendLinesNumber;
  private String fileID;
  private String filePath = "";
  private DoubleProperty avaliableSpace;
  private boolean sysntacticDetailsVisible = false;
  private boolean semanticDetailsVisible = false;
  private final Label fileIDL;
  private final Label fileIDL2;
  private BorderPane syntacticPane;
  private BorderPane semanticPane;
  private Label synPercentageL;
  private Label semPercentageL;
  private Label synTitleL;
  private Label semTitleL;
  private ProgressBar syntacticPB;
  private ProgressBar semanticPB;
  private TextArea synDetailsTA;
  private TextArea semDetailsTA;
  private Button synShowDetailsB;
  private Button semShowDetailsB;
  private final Application application;
  
  public ProgressPane(Stage primaryStage, Application application, String filePath, long totalLinesNumber) {
    this.application = application;
    this.filePath = filePath;
    this.totalLinesNumber = totalLinesNumber;
    totalSendLinesNumber = totalLinesNumber;
    setId("grid");
    prefWidthProperty().bind(primaryStage.widthProperty().subtract(16));
    prefHeightProperty().bind(primaryStage.heightProperty().subtract(38));
    setMinWidth(minWidth);
    setVgap(20);
    avaliableSpace = new SimpleDoubleProperty();
    avaliableSpace.bind(prefHeightProperty().subtract(getPadding().getTop()).subtract(getPadding().getBottom()).subtract(125));
    
    HBox fileIDHBox = new HBox(7);
    fileIDL = new Label("Nombre del archivo:");
    fileIDL2 = new Label(String.valueOf(filePath));
    fileIDHBox.getChildren().setAll(fileIDL, fileIDL2);
    
    syntacticPane = new BorderPane();
    synPercentageL = new Label("Líneas completadas / Líneas totales");
    syntacticPB = new ProgressBar(0);
    synDetailsTA = new TextArea();
    synShowDetailsB = new Button(showText);
    synTitleL = new Label("Revisión Sintáctica");
    initProgressPane(syntacticPane, synPercentageL, synTitleL, syntacticPB, synDetailsTA, synShowDetailsB, syntactic);
    
    semanticPane = new BorderPane();
    semPercentageL = new Label("Líneas completadas / Líneas totales");
    semanticPB = new ProgressBar(0);
    semDetailsTA = new TextArea();
    semShowDetailsB = new Button(showText);
    semTitleL = new Label("Revisión Semántica");
    initProgressPane(semanticPane, semPercentageL, semTitleL, semanticPB, semDetailsTA, semShowDetailsB, semantic);
    
    GridPane.setConstraints(fileIDHBox, 0, 0);
    GridPane.setConstraints(syntacticPane, 0, 1);
    GridPane.setConstraints(semanticPane, 0, 2);
    getChildren().setAll(fileIDHBox, syntacticPane, semanticPane);
  }

  /**
   * Inicializa cada nodo dentro del panel pane
   *
   * @param pane
   * @param titleL
   * @param progressBar
   * @param detailsTA
   * @param showDetailsB
   * @param validationType
   */
  private void initProgressPane(final BorderPane pane, final Label percentageL, final Label titleL, final ProgressBar progressBar, final TextArea detailsTA, final Button showDetailsB, final int validationType) {
    pane.getStyleClass().add("details-container");
    pane.setPrefHeight(prefPanelHeight);
    pane.setMinWidth(minWidth - getPadding().getLeft() - getPadding().getRight() + 36);
    
    percentageL.prefWidthProperty().bind(this.prefWidthProperty().subtract(this.getPadding().getLeft()).subtract(this.getPadding().getRight()));
    percentageL.setAlignment(Pos.CENTER);
    
    progressBar.prefWidthProperty().bind(this.prefWidthProperty().subtract(this.getPadding().getLeft()).subtract(this.getPadding().getRight()));
    progressBar.setMinWidth(minWidth - getPadding().getLeft() - getPadding().getRight() - pane.getPadding().getLeft() - pane.getPadding().getRight());
    
    detailsTA.prefWidthProperty().bind(this.prefWidthProperty().subtract(this.getPadding().getLeft()).subtract(this.getPadding().getRight()));
    detailsTA.setMinWidth(minWidth - getPadding().getLeft() - getPadding().getRight() - pane.getPadding().getLeft() - pane.getPadding().getRight());
    detailsTA.setMinHeight(minHeight);
    detailsTA.setEditable(false);
    detailsTA.setFocusTraversable(false);
    
    showDetailsB.getStyleClass().add("details-button");
    showDetailsB.prefWidthProperty().bind(this.prefWidthProperty().subtract(this.getPadding().getLeft()).subtract(this.getPadding().getRight()));
    showDetailsB.setMinWidth(minWidth - getPadding().getLeft() - getPadding().getRight() - pane.getPadding().getLeft() - pane.getPadding().getRight());
    showDetailsB.setOnAction(new EventHandler<ActionEvent>() {
      
      @Override
      public void handle(ActionEvent event) {
        boolean detailsVisible = validationType == syntactic ? sysntacticDetailsVisible : semanticDetailsVisible;
        if (detailsVisible) {
          showDetailsB.setText(showText);
          pane.setCenter(null);
          pane.prefHeightProperty().unbind();
          pane.setPrefHeight(prefPanelHeight);
        } else {
          showDetailsB.setText(hideText);
          pane.setCenter(detailsTA);
          pane.prefHeightProperty().bind(avaliableSpace);
        }
        if (validationType == syntactic) {
          sysntacticDetailsVisible = !sysntacticDetailsVisible;
        } else {
          semanticDetailsVisible = !semanticDetailsVisible;
        }
      }
    });
    
    VBox synVBox = new VBox(5);
    synVBox.getStyleClass().add("top-container");
    synVBox.getChildren().setAll(titleL, percentageL, progressBar);
    pane.setTop(synVBox);
    pane.setBottom(showDetailsB);
  }

  /**
   * Inicializa el thread de consulta y relaciona su progreso con los elementos
   * graficos que informan al usuario del avance.
   *
   * @param fileAnalysisTask
   */
  protected Task createSyntacticValidationTask() {
    CheckSyntacticValidationProgressTask fileAnalysisTask = new CheckSyntacticValidationProgressTask(filePath);
    syntacticPB.progressProperty().unbind();
    syntacticPB.setProgress(0);
    syntacticPB.progressProperty().bind(fileAnalysisTask.getTheValidatorThread().progressProperty());
    fileAnalysisTask.getTheValidatorThread().progressProperty().addListener(
        new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number oldLinesNumber, Number newLinesNumber) {
            synPercentageL.setText(((int) (newLinesNumber.doubleValue() * totalLinesNumber)) + " / " + totalLinesNumber);
            }
        });
    fileAnalysisTask.getTheValidatorThread().messageProperty().addListener(
        new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> arg0, String oldMessage, String newMessage) {
            synDetailsTA.appendText(newMessage + "\n");
            }
        });
    return fileAnalysisTask;
  }

  

  /**
   *
   * @return
   */
  protected Task createSemanticValidationTask() {
    Task fileAnalysisTask = checkSemanticValidationProgress();
    semanticPB.progressProperty().unbind();
    semanticPB.setProgress(0);
    semanticPB.progressProperty().bind(fileAnalysisTask.progressProperty());
    fileAnalysisTask.progressProperty().addListener(
            new ChangeListener<Number>() {
              
              @Override
              public void changed(ObservableValue<? extends Number> arg0, Number oldLinesNumber, Number newLinesNumber) {
                semPercentageL.setText(((int) (newLinesNumber.doubleValue() * totalSendLinesNumber)) + " / " + totalSendLinesNumber);
                if (newLinesNumber.intValue() == 1) {
                  ((MainWindow) application).endFileAnalysis();
                  semDetailsTA.textProperty().unbind();
                }
              }
            });
    fileAnalysisTask.messageProperty().addListener(
            new ChangeListener<String>() {
              
              @Override
              public void changed(ObservableValue<? extends String> arg0, String oldMessage, String newMessage) {
                semDetailsTA.appendText(newMessage);
              }
            });
    return fileAnalysisTask;
  }

  /**
   *
   * @return
   */
  private Task checkSemanticValidationProgress() {
    return new Task() {
      
      @Override
      protected Object call() throws Exception {
        fileID = "1";//esperando ID de camilo
        int completedLines = 0;
        TransactionResultServiceControl resultsControl;
        try {
          resultsControl = new TransactionResultServiceControl();
        } catch (Exception e) {
          updateMessage("\nOcurrio un error al comenzar la validación semántica.");
          return true;
        }
        resultsControl.startRevision(fileID);
        String message;
        while (completedLines < totalSendLinesNumber) {
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            System.err.println("Error con la espera entre solicitudes de nuevas trazas.");
          }
          message = "";
          List<TransactionResult> analysedTransactions = resultsControl.transactionResultByFile(fileID);
          completedLines += analysedTransactions.size();
          for (TransactionResult transactionResult : analysedTransactions) {
            message += "Transacción " + transactionResult.getTransactionId() + ": " + transactionResult.getValidationResult() + "\n";
          }
          updateMessage(message);
          updateProgress(completedLines, totalSendLinesNumber);
          if (isCancelled()) {
            break;
          }
        }
        updateMessage("\nAnálisis semántico completado.");
        return true;
      }
    };
  }

  /**
   * Para darle tiempo al textarea y que se pueda actualizar
   *
   * @throws InterruptedException
   */
  public static void waitSomeTime() throws InterruptedException {
    Thread.sleep(new Random(System.currentTimeMillis()).nextInt(400));
  }
}
